﻿//tool.cpp
#include <QGuiApplication>
#include <QScreen>

#include "tool.h"
QString sysMain = "FR";
bool isLog = true;
QString sysLogPath="log";
QString sysLogName="log";
QStringList sysComList;
QList<int> sysScreenWidth;
int curScreenWidth=1920;

void setLog(bool log){
    isLog = log;
}

int getIntToMark(int mark){
    if(mark == 0)
        return 0;
    if(mark > 0)
        return 1;
    return -1;
}

QString getCurPath(void){
    // return QDir::currentPath();
    QFileInfo path(QCoreApplication::applicationFilePath());

    // QFileInfo path(QDir::currentPath());
    // // retInfo(QDir::currentPath());
    // if(path.baseName().toUpper()==sysMain){
    //     return QDir::currentPath();
    // }
    // // retInfo(path.path());
    return QString("%0").arg(path.path());
}

int getScreenNums(void)
{
    return sysScreenWidth.count();
}

void getSysScreen(void){
    sysScreenWidth.clear();
    QList<QScreen *> list_screen = QGuiApplication::screens();
    // 通过循环可以遍历每个显示器
    for (int i = 0; i < list_screen.size(); i++)
    {
        QRect rect = list_screen.at(i)->geometry();
        sysScreenWidth.append(rect.width());
//        int desktop_width = rect.width();
//        int desktop_height = rect.height();
        // 打印屏幕分辨率
//        qDebug() << desktop_width <<desktop_height;
    }
}

bool containsChinese(const QString str){
    QString pattern = "[\u4e00-\u9fa5]";
    QRegExp rx(pattern);
    return str.contains(rx);
}

QString getDirName(const QString format){
    QDateTime time = QDateTime::currentDateTime();
    return time.toString(format);
}

QString getPathName(const QString path,const QString name){
    return QString("%0/%1").arg(path).arg(name);
}

//获取文件编码
void getFilename(const QString name, int (&no)[2]){
    QString filename=name;
    if(name[name.size()-1]=='F')
    {
        filename.chop(1);
    }
    no[0]=0;
    no[1]=0;
    QStringList sl = filename.split('_');
    if(sl.count()==0){
        return;
    }
    no[0] = sl[0].toInt();
    if(sl.count()>1){
        no[1] = sl[1].toInt();
    }
}

//设置文件名称
void setFilename(int num,QString &name,const QString dir,const QString ext,int fileLen){
    QDir d(dir);
    if(!d.exists()){
        d.mkpath(dir);
    }
    name = dir;
    name += QString("/%0").arg(num,fileLen,10,QLatin1Char('0'));
    name += QString(".%0").arg(ext);
}

bool is4KScreen(void)
{
    return (curScreenWidth == 3840);
}

void set4KScreen(int x){
    for(int i=0;i<getScreenNums();i++){
        if(sysScreenWidth[i]==x){
            curScreenWidth = x;
        }
    }
}

QString getSpinBoxSize(int fontSize,int width,int height){
    QString s = QString("font-size: %0px;").arg(fontSize);
    QString sw = "";
    QString sh = "";
    if(width){
        sw = QString(" min-width: %0px; max-width: %1px;").arg(width).arg(width);
    }
    if(height){
        sh = QString(" min-height: %0px; max-height: %1px;").arg(height).arg(height);
    }
    QString shell = QString("QSpinBox { %0 %1 %2 }").arg(s).arg(sw).arg(sh);
    return shell;
}

QString getLabelSize(int fontSize,int width,int height){
    QString s = QString("font-size: %0px;").arg(fontSize);
    QString sw = "";
    QString sh = "";
    if(width){
        sw = QString(" min-width: %0px; max-width: %1px;").arg(width).arg(width);
    }
    if(height){
        sh = QString(" min-height: %0px; max-height: %1px;").arg(height).arg(height);
    }
    QString shell = QString("QLabel { %0 %1 %2 }").arg(s).arg(sw).arg(sh);
    return shell;
}

QString getPushButtonSize(int fontSize,int width,int height){
    QString s = QString("font-size: %0px;").arg(fontSize);
    QString sw = "";
    QString sh = "";
    if(width){
        sw = QString(" min-width: %0px; max-width: %1px;").arg(width).arg(width);
    }
    if(height){
        sh = QString(" min-height: %0px; max-height: %1px;").arg(height).arg(height);
    }
    QString shell = QString("QPushButton { %0 %1 %2 }").arg(s).arg(sw).arg(sh);
    return shell;
}

QString getComboBoxSheet(int h){
    return QString("QAbstractItemView::item{height: %0px;}").arg(h);
}

bool winIsScreen(int x,int width){
    int w=0;
    w = sysScreenWidth[0];
    retInfo(QString("%0 %1 %2").arg(x).arg(width).arg(w));
    if((x+width)<=w){
        return true;
    }
    if(getScreenNums()==2)
    {//2个screen
        if(x<w){
            return false;
        }
        w += sysScreenWidth[1];
        retInfo(QString("%0 %1 %2").arg(x).arg(width).arg(w));
        if((x+width)<=w){
            return true;
        }
    }
    return false;
}

void exeLinuxCmd(const QString cmd, QString &strRet, QString &strErr){
    QProcess p;
    p.start("bash", QStringList() << "-c" << cmd);
    p.waitForFinished();
    strRet = p.readAllStandardOutput();
    strErr = p.readAllStandardError();
}

QString getNumber(const float N,const int dec){
    return QString::number(N, 'f', dec);
}

int getComPos(const QString com){
    return com.right(1).toInt();
}

int getComIndex(const int pos){
    for(int i=0;i<sysComList.count();i++) {
        if(pos == sysComList[i].right(1).toInt()){
            return i;
        }
    }
    return -1;
}

void getSysCom(const QString limit){
    sysComList.clear();
    QSerialPort sw;
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
        sw.setPort(info);
        if(sw.open(QIODevice::ReadWrite)){
            qDebug() << sw.portName() << "," << limit << "," << limit.compare(sw.portName());
            sysComList.append(sw.portName());
            sw.close();
        }
    }
    qDebug() << sysComList;
}

bool saveImageEx(const QString name,const int Dpi, const int Rotate, QImage *img)
{
//    retInfo(QString("saveImageEx %0 %1 %2").arg(name).arg(Dpi).arg(Rotate));

    QMatrix matrix;
    matrix.rotate(Rotate);

    bool ret;
    if(img != nullptr){
        img->setDotsPerMeterX(float(Dpi)*39.37);
        img->setDotsPerMeterY(float(Dpi)*39.37);
        if(Rotate != 0){
            *img = img->transformed(matrix);
        }
        ret = img->save(name);
    }else{
        QImage _img;
        _img.load(name);
        _img.setDotsPerMeterX(float(Dpi)*39.37);
        _img.setDotsPerMeterY(float(Dpi)*39.37);
        if(Rotate != 0){
            _img = _img.transformed(matrix);
        }
        ret = _img.save(name);
    }
//    qDebug()<<"save image " << name << "dpi=" << Dpi << "  ret=" << ret;
    return ret;
}

//void setLogPath(const QString path)
//{
//    sysLogPath = QString("%0/FS/log").arg(path);
//    retInfo(sysLogPath);
//}

void retInfo(const QString msg)
{
    QTime curTime = QTime::currentTime();
    QString strTime = curTime.toString("hh:mm:ss.zzz");
    qDebug()<< strTime << msg;
    saveLog(msg);
}

//void retInfos(const QString msg, ...)
//{
//　　va_list arg_ptr;

//　　va_start(arg_ptr, i);
//　　j=va_arg(arg_ptr, int);
//　　va_end(arg_ptr);
//　　printf("%d %d/n", i, j);
//　　return;
//}

void saveError(const QString msg, int errRet, int ok)
{
    QString err;
    err = QString("%0 error= %1").arg(msg).arg(errRet);
    if(errRet != ok){
        qDebug()<< err;
        saveLog(err);
    }
}

void saveLogName(const QString msg,const QString fname){
    QTime curTime = QTime::currentTime();
    QString name=QString("%0/%1/%2.txt").arg(getCurPath()).arg(sysLogPath).arg(fname);
    QFile file(name);
    file.open(QIODevice::WriteOnly|QIODevice::Append);
    QTextStream textStr(&file);
    textStr.setCodec("UTF-8");
    textStr<<curTime.toString("hh:mm:ss.zzz ")<<msg<<"\n";
    file.flush();
    file.close();
}

void saveLog(const QString msg)
{
    if(!isLog)return;
    QDate curDate = QDate::currentDate();
    QTime curTime = QTime::currentTime();
    QString name=QString("%0/%1/%2-%3.txt").arg(getCurPath()).arg(sysLogPath).arg(sysLogName).arg(curDate.toString("yyMMdd"));
    QFile file(name);
    file.open(QIODevice::WriteOnly|QIODevice::Append);
    QTextStream textStr(&file);
    textStr.setCodec("UTF-8");
    textStr<<curTime.toString("hh:mm:ss.zzz ")<<msg<<"\n";
    file.flush();
    file.close();
}

void qStrToCstr(const QString q_str,char *v_str,size_t size)
{
    QString s = q_str;

    QByteArray ba = s.toUtf8();
    memcpy((void *)v_str,ba.data(),size);
}

int qStrToInt(const QString q_str)
{
    return q_str.toInt();
}

float qStrToFloat(const QString q_str)
{
    return q_str.toFloat();
}

void qStrToInts(const QString q_str,int *v_ints,size_t size)
{
    QStringList tempList =  q_str.split(",");
    for (int index = 0;index < tempList.count(); index++) {
        if(index < (int)size){
            v_ints[index] = qStrToInt(tempList[index]);
        }
    }
}

QString renameTemp(const QString name,int count){
    QString temp;
    QFileInfo info(name);
    temp = QString("%0/%1_temp%2.%3")
            .arg(info.absolutePath())
            .arg(info.baseName())
            .arg(count).arg(info.suffix());
    return temp;
}

void initRand(void){
    qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
}


QString getImageInfo(const QImage::Format imgFormat){
    switch(imgFormat){
    case QImage::Format_Mono:
        return QString("单色图像");
    case QImage::Format_Grayscale8:
        return QString("256灰度图像");
    case QImage::Format_RGB888:
        return QString("24位彩色图像");
    }
    return QString("其它[%0]").arg(int(imgFormat));
}

cv::Mat cvRead(const QString name,const int flags){
    // retInfo(QString("cvRead [%0] %1").arg(name).arg(containsChinese(name)));
    QFile file(name);
    cv::Mat image;
    if(containsChinese(name)&&file.open(QIODevice::ReadOnly)){
        //中文名称，打开二进制文件
        QByteArray byteArray = file.readAll();
        std::vector<char> data(byteArray.data(),byteArray.data()+byteArray.size());
        image = cv::imdecode(cv::Mat(data),flags);
        file.close();
    }else{
        image = cv::imread(name.toStdString(), flags);
    }
    return image;
}

void cvWriteBmp(const cv::Mat inMat, const QString name){

}
void cvWriteJpg(const cv::Mat inMat, const QString name){

}
void cvWriteTiff(const cv::Mat inMat, const QString name){

}
void cvWritePng(const cv::Mat inMat, const QString name){

}

//保存文件
void cvMatImageSave(const cv::Mat inMat, const QString name,bool isNeg,int saveFormat,int para){
    // retInfo(QString("cvMatImageSave [%0] %1 %2 %3").arg(name).arg(isNeg).arg(saveFormat).arg(para));
    cv::Mat save_image;
    if(isNeg){
        if(inMat.type() == CV_8UC3){
            save_image = cv::Scalar(255,255,255) - inMat;
        }else{
            save_image = cv::Scalar(255) - inMat;
        }
    }else{
        save_image = inMat;
    }
    std::vector<unsigned char>buf;
    buf.clear();
    switch(saveFormat){
    case 0:
        // cv::imwrite(name.toStdString(), save_image);
        cv::imencode(".bmp", save_image, buf);
        break;
    case 1:
        //jpg
        {
            std::vector<int>params={cv::IMWRITE_JPEG_QUALITY,para};
            // cv::imwrite(name.toStdString(), save_image, params);
            cv::imencode(".jpg", save_image, buf, params);
        }
        break;
    case 2:
        //tiff
        // cv::imwrite(name.toStdString(), save_image);
        cv::imencode(".tiff", save_image, buf);
        break;
    case 3:
        //png
        {
            std::vector<int>params = {cv::IMWRITE_PNG_COMPRESSION,para};
            // cv::imwrite(name.toStdString(), save_image, params);
            cv::imencode(".png", save_image, buf, params);
        }
        break;
    }
    QFile file(name);
    if(buf.size()>0 && file.open(QIODevice::WriteOnly)){
        file.write((char *)&buf[0], buf.size());
        file.close();
    }
}

QImage  cvMatToQImage( const cv::Mat &inMat )
{
    switch ( inMat.type() )
    {
        // 8-bit, 4 channel
        case CV_8UC4:
        {
            QImage image( inMat.data,
                          inMat.cols, inMat.rows,
                          static_cast<int>(inMat.step),
                          QImage::Format_ARGB32 );

            return image;
        }
        // 8-bit, 3 channel
        case CV_8UC3:
        {
            QImage image( inMat.data,
                          inMat.cols, inMat.rows,
                          static_cast<int>(inMat.step),
                          QImage::Format_RGB888 );

            return image.rgbSwapped();
        }
        // 8-bit, 1 channel
        case CV_8UC1:
        {
            QImage image( inMat.data,
                          inMat.cols, inMat.rows,
                          static_cast<int>(inMat.step),
                          QImage::Format_Grayscale8 );
            return image;
        }
        default:
            retInfo(QString("CVS::cvMatToQImage() - cv::Mat image type not handled in switch: %0").arg(inMat.type()));
            break;
        }
        return QImage();
}

QPixmap cvMatToQPixmap( const cv::Mat &inMat )
{
    return QPixmap::fromImage( cvMatToQImage( inMat ));
}

cv::Scalar qcolor2scalar(QColor color)
{
    int r,g,b;
    color.getRgb(&r, &g, &b);
    return cv::Scalar(b,g,r);
}

int imageKsjToMat(unsigned char* pImageData, int nWidth, int nHeight, int nBitCount, cv::Mat **image){
    int nType = (nBitCount == 8) ? CV_8UC1:CV_8UC3;
    int nLineByte = (((nWidth * nBitCount) + 31) / 32) * 4;
    *image =new cv::Mat(nHeight,nWidth,nType,pImageData,nLineByte);
    cv::flip(**image,**image,0);
    **image = (*image)->clone();
    return 0;
}

// int  getMvsType(int nValue){
//     if(nValue == 0x18000A){
//         return 1;
//     }
//     return 0;
// }

// int  getMvsValue(int nType){
//     if(nType == 1){
//         return 0x18000A;
//     }
//     return 0x1080001;
// }

// ch:像素排列由RGB转为BGR | en:Convert pixel arrangement from RGB to BGR
void RGB2BGR( unsigned char* pRgbData, unsigned int nWidth, unsigned int nHeight )
{
    if ( NULL == pRgbData )
    {
        return;
    }
    // red和blue数据互换
    for (unsigned int j = 0; j < nHeight; j++)
    {
        for (unsigned int i = 0; i < nWidth; i++)
        {
            unsigned char red = pRgbData[j * (nWidth * 3) + i * 3];
            pRgbData[j * (nWidth * 3) + i * 3]     = pRgbData[j * (nWidth * 3) + i * 3 + 2];
            pRgbData[j * (nWidth * 3) + i * 3 + 2] = red;
        }
    }
}

// cv::Mat imageMvsToMat(unsigned char* pImageData, int nWidth, int nHeight, int nValue){
    // cv::Mat mDst;

    // if(getMvsType(nValue) == 1){
        // Mat像素排列格式为BGR，需要转换
        // RGB2BGR(pImageData, nWidth, nHeight);
        // mDst = cv::Mat(nHeight, nWidth, CV_8UC3, pImageData);
        // ByaerRG8->BGR
        // MvGvspPixelType enDstPixelType = PixelType_Gvsp_BGR8_Packed;
//     }else{
//         mDst = cv::Mat(nHeight, nWidth, CV_8UC1, pImageData);
//     }
//     return mDst;
// }


//KSJ图像数据转换cv::Mat
cv::Mat imageKsjToMat(unsigned char* pImageData, int nWidth, int nHeight, int nBitCount)
{
    cv::Mat mDst;
    int nType = (nBitCount == 8) ? CV_8UC1:CV_8UC3;
//    int nLineByte = (((nWidth * nBitCount) + 31) / 32) * 4;
    int nBandNum = (nBitCount>>3);
    mDst = cv::Mat::zeros(cv::Size(nWidth, nHeight), nType);
    for (int j = 0; j < nHeight; ++j)
    {
        unsigned char* data = mDst.ptr<unsigned char>(j);
        unsigned char* pSubBuffer = pImageData + (j + 1) * nWidth  * nBandNum;
        memcpy(data, pSubBuffer, nWidth * nBandNum);
    }
    memcpy(mDst.data, pImageData, nWidth*nHeight*nBandNum);
//    mDst = cv::Mat(nHeight,nWidth,nType,pImageData,nLineByte);
    cv::flip(mDst,mDst,0);
    return mDst;
}

cv::Mat matResize(const cv::Mat &image, int sWidth, int sHeight, float &scale){
    scale = imageScale(image.size().width,image.size().height,sWidth,sHeight);
    int w = int(image.size().width/scale);
    int h = int(image.size().height/scale);
    cv::Size dsize = cv::Size(w,h);
    cv::Mat result = cv::Mat(dsize, image.type());
//    //等比缩小
    cv::resize(image, result, dsize);
    return result;
}

float imageScale(int nWidth, int nHeight,int sWidth, int sHeight){
    float s1 = (float)nWidth/(float)sWidth;
    float s2 = (float)nHeight/(float)sHeight;
    return (s1 > s2) ? s1 : s2;
}

void sortBox(const QVector<cv::Rect> inBox, QVector<cv::Rect> &outBox){
    cv::Rect box;
    QVector<cv::Rect> boxList1,boxList2;
    boxList1.clear();
    foreach (box, inBox) {
        boxList1.append(box);
    }
    boxList2.clear();
    while(!boxList1.isEmpty()){
        box = boxList1.takeFirst();
        int pos=0;
        //比较2
        while(true){
            if(pos == boxList2.count()){
                break;
            }
            if(box.x < boxList2[pos].x){
                break;
            }
            pos++;
        }
        boxList2.insert(pos,box);
    }
    outBox.clear();
    foreach (box, boxList2) {
        // retInfo(QString("sort %0 %1 %2 %3").arg(box.x).arg(box.y).arg(box.width).arg(box.height));
        outBox.append(box);
    }
}

bool rectInRect(const cv::Rect &rectIn,const cv::Rect &rectOut){
    return rectIn == (rectIn & rectOut);
}

float getAngle(const cv::Size size){
    float angle = 0;

    angle = fabsf(float(size.width) / float(size.height));
    angle = atan(angle);
    angle = angle * 180 / CV_PI;
    return angle;
}

float getPointAngle2(const cv::Point2f pointO, const cv::Point2f pointA)
{
    float angle = 0;
    float temp;
    cv::Point2f point;

    point = cv::Point2f((pointA.x - pointO.x), (pointA.y - pointO.y));

    if ((0 == point.x) && (0 == point.y))
    {//零点
        return 0.0;
    }
    if (0 == point.x)
    {//X零点
        if (point.y > 0)
        {
            angle = 180.0;
        }
        if (point.y <0)
        {
            angle = 0.0;
        }
        return angle;
    }
    if (0 == point.y)
    {//Y零点
        if (point.x > 0)
        {
            angle = 90.0;
        }
        if (point.x <0)
        {
            angle = 270.0;
        }
        return angle;
    }
    temp = fabsf(float(point.y) / float(point.x));
    temp = atan(temp);
    temp = temp * 180 / CV_PI;
    angle = temp;
    if ((0 < point.x) && (0 > point.y)) //图像坐标系下 p1在p0的右上角；
    {
        angle = 90 - temp;
        return angle;
    }
    if ((0<point.x) && (0<point.y))     //图像坐标系下 p1在p0的右下角；
    {
        angle = 90 + temp ;
        return angle;
    }
    if ((0>point.x) && (0<point.y))     //图像坐标系下 p1在p0的左下角；
    {
        angle = 270 - temp ;
        return angle;
    }
    if ((0>point.x) && (0>point.y))     //图像坐标系下 p1在p0的左上角；
    {
        angle = 360 - temp;
        return angle;
    }
    return angle;
}

//int getPointToPointDirect(const cv::Point2f pts[])
//{
//    int d=0;
//    double res1 = sqrt(pow(pts[0].x - pts[1].x, 2) + pow(pts[0].y - pts[1].y, 2));
//    double res2 = sqrt(pow(pts[1].x - pts[2].x, 2) + pow(pts[1].y - pts[2].y, 2));
//    if(res2>res1){
//        d=1;
//    }
//    return d;
//}

//float getPointToPointAngle(const cv::Point2f pts[])
//{
//    int d = getPointToPointDirect(pts);
//    return getPointAngle2(pts[d+0], pts[d+1]);
//}

float imageCmpDiff(const cv::Mat image1,const cv::Mat image2)
{
    cv::Mat matDst1, matDst2, matDiff;
    if(image1.empty()||image2.empty()){
        return 0.0;
    }
//    retInfo(QString("imageCmpDiff (%0,%1) (%2,%3)").arg(image1.rows).arg(image1.cols).arg(image2.rows).arg(image2.cols));
//    int height = qMin(image1.rows,image2.rows);
//    int width = qMin(image1.cols,image2.cols);
    int height = image1.rows;
    int width = image1.cols;
    //统一尺寸
    cv::resize(image1, matDst1, cv::Size(width, height));
    cv::resize(image2, matDst2, cv::Size(width, height));
    //灰度化
    if(matDst1.type() == CV_8UC3){
        cv::cvtColor(matDst1, matDst1, cv::COLOR_BGR2GRAY);
    }
    if(matDst2.type() == CV_8UC3){
        cv::cvtColor(matDst2, matDst2, cv::COLOR_BGR2GRAY);
    }
    absdiff(matDst1, matDst2, matDiff);
//    int num = countNonZero(matDiff);
    int num = 0;
    for (int i = 0; i < matDiff.rows; i++){
        for (int j = 0; j < matDiff.cols; j++){
            if (matDiff.at<uchar>(i,j)>5){
                num++;
            }
        }
    }
    return 100.0 - (float(num) / float(matDiff.rows*matDiff.cols) * 100.0);
}

#define MATCMPNUMS 16
#define MATCMPNUMS2 256

float imageCmp(const cv::Mat image1,const cv::Mat image2){
    cv::Mat matDst1, matDst2;
    // 缩小尺寸：将图像缩小到8*8的尺寸，总共64个像素。这一步的作用是去除图像的细节，只保留结构/明暗等基本信息，摒弃不同尺寸/比例带来的图像差异；
    cv::resize(image1, matDst1, cv::Size(MATCMPNUMS, MATCMPNUMS));
    cv::resize(image2, matDst2, cv::Size(MATCMPNUMS, MATCMPNUMS));
    //灰度化
    if(matDst1.type() == CV_8UC3){
        cv::cvtColor(matDst1, matDst1, cv::COLOR_BGR2GRAY);
    }
    if(matDst2.type() == CV_8UC3){
        cv::cvtColor(matDst2, matDst2, cv::COLOR_BGR2GRAY);
    }
    int iAvg1 = 0, iAvg2 = 0;
    int arr1[MATCMPNUMS2], arr2[MATCMPNUMS2];
    for (int i = 0; i < MATCMPNUMS; i++) {
        //位置是第i行的头指针
        uchar* data1 = matDst1.ptr<uchar>(i);
        uchar* data2 = matDst2.ptr<uchar>(i);
        int tmp = i * MATCMPNUMS;
        for (int j = 0; j < MATCMPNUMS; j++) {
            int tmp1 = tmp + j;
            arr1[tmp1] = data1[j] / (MATCMPNUMS/2) ;
            arr2[tmp1] = data2[j] / (MATCMPNUMS/2) ;
            iAvg1 += arr1[tmp1];
            iAvg2 += arr2[tmp1];
        }
    }
    iAvg1 /= MATCMPNUMS2;
    iAvg2 /= MATCMPNUMS2;
    for (int i = 0; i < MATCMPNUMS2; i++) {
        arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0;
        arr2[i] = (arr2[i] >= iAvg2) ? 1 : 0;
    }
    int iDiffNum = 0;
    for (int i = 0; i < MATCMPNUMS2; i++)
        if (arr1[i] != arr2[i])
            ++iDiffNum;
    return float(MATCMPNUMS2-iDiffNum)/(float)MATCMPNUMS2*100.0;
}

//float imageCmpOrb(const cv::Mat image1,const cv::Mat image2){
//    //建立
//    Ptr<ORB> orb = ORB::create();
//    vector<KeyPoint> Keypoints1,Keypoints2;
//    Mat descriptors1,descriptors2;
//    //检测
//    orb->detectAndCompute(rgbd1, Mat(), Keypoints1, descriptors1);
//    orb->detectAndCompute(rgbd2, Mat(), Keypoints2, descriptors2);
//    retInfo(QString("Key points %0 %1").arg(Keypoints1.size()).arg(Keypoints2.size()));
//    //匹配
//    vector<DMatch> matches;
//    Ptr<DescriptorMatcher> matcher =DescriptorMatcher::create("BruteForce");
//    matcher->match(descriptors1, descriptors2, matches);
//    retInfo(QString("find out total %0").arg(matches.size()));
//    //比较值
//    float diff = (float)(Keypoints1.size()+Keypoints2.size())/2.0;
//    return diff/(float)matches.size()*100.0;
//}

int getRotateValue(int index)
{
    switch(index){
    case 1:
        return 270;
    case 2:
        return 90;
    case 3:
        return 180;
    default:
        return 0;
    }
}

int getWidthHeightFormat(int width,int height,int iwidth,int iheight, float format)
{
    float fw = float(iwidth)/float(width);
    float fh = float(iwidth)/float(width);
    int f = 0;
    if(fw>format){
        f++;
    }
    if(fh>format){
        f++;
    }
    saveLog(QString("%0-%1,%2-%3,%4-%5,%6")
                .arg(width).arg(height)
                .arg(iwidth).arg(iheight)
                .arg(int(fw*100.0)).arg(int(fh*100.0))
                .arg(f));
    return f;
}

float matLightMean(const cv::Mat image)
{
    cv::Scalar scalar = cv::mean(image);
    if(image.type() == CV_8UC3){
//        retInfo(QString("matLightMean %0 %1 %2").arg(scalar.val[0]).arg(scalar.val[1]).arg(scalar.val[2]));
        return float((scalar.val[0]+scalar.val[1]+scalar.val[2])/3.0);
    }else{
//        retInfo(QString("matLightMean %0").arg(scalar.val[0]));
        return float(scalar.val[0]);
    }
}

float nameLightMean(const QString name)
{
    cv::Mat im = cvRead(name, cv::IMREAD_UNCHANGED);
    return matLightMean(im);
}

float matLightClearness(const cv::Mat image)
{
/* 检测模糊度: 返回值为模糊度，值越大越模糊，越小越清晰，范围在0到几十，10以下相对较清晰，一般为5;
    调用时可在外部设定一个阀值，具体阈值根据实际情况决定，返回值超过阀值当作是模糊图片;
*/
    cv::Mat img;
    if(image.type() == CV_8UC3){
        // 将输入的图片转为灰度图，使用灰度图检测模糊度
        cv::cvtColor(image, img, cv::COLOR_BGR2GRAY);
    }else{
        img = image;
    }
    //图片每行字节数及高
    int width = img.cols;
    int height = img.rows;
    ushort* sobelTable = new ushort[width*height];
    memset(sobelTable, 0, width*height*sizeof(ushort));

    int i, j, mul;
    //指向图像首地址
    uchar* udata = img.data;
    for (i = 1, mul = i*width; i < height - 1; i++, mul += width)
        for (j = 1; j < width - 1; j++)
            sobelTable[mul + j] = abs(udata[mul + j - width - 1] + 2 * udata[mul + j - 1] + udata[mul + j - 1 + width] -
                                      udata[mul + j + 1 - width] - 2 * udata[mul + j + 1] - udata[mul + j + width + 1]);
    for (i = 1, mul = i*width; i < height - 1; i++, mul += width)
        for (j = 1; j < width - 1; j++)
            if (sobelTable[mul + j] < 50 || sobelTable[mul + j] <= sobelTable[mul + j - 1] ||
                sobelTable[mul + j] <= sobelTable[mul + j + 1]) sobelTable[mul + j] = 0;

    int totLen = 0;
    int totCount = 1;

    uchar suddenThre = 50;
    uchar sameThre = 3;
    //遍历图片
    for (i = 1, mul = i*width; i < height - 1; i++, mul += width)
    {
        for (j = 1; j < width - 1; j++)
        {
            if (sobelTable[mul + j])
            {
                int   count = 0;
                uchar tmpThre = 5;
                uchar max = udata[mul + j] > udata[mul + j - 1] ? 0 : 1;

                for (int t = j; t > 0; t--)
                {
                    count++;
                    if (abs(udata[mul + t] - udata[mul + t - 1]) > suddenThre)
                        break;

                    if (max && udata[mul + t] > udata[mul + t - 1])
                        break;

                    if (!max && udata[mul + t] < udata[mul + t - 1])
                        break;

                    int tmp = 0;
                    for (int s = t; s > 0; s--)
                    {
                        if (abs(udata[mul + t] - udata[mul + s]) < sameThre)
                        {
                            tmp++;
                            if (tmp > tmpThre) break;
                        }
                        else break;
                    }
                    if (tmp > tmpThre) break;
                }

                max = udata[mul + j] > udata[mul + j + 1] ? 0 : 1;

                for (int t = j; t < width; t++)
                {
                    count++;
                    if (abs(udata[mul + t] - udata[mul + t + 1]) > suddenThre)
                        break;

                    if (max && udata[mul + t] > udata[mul + t + 1])
                        break;

                    if (!max && udata[mul + t] < udata[mul + t + 1])
                        break;

                    int tmp = 0;
                    for (int s = t; s < width; s++)
                    {
                        if (abs(udata[mul + t] - udata[mul + s]) < sameThre)
                        {
                            tmp++;
                            if (tmp > tmpThre) break;
                        }
                        else break;
                    }

                    if (tmp > tmpThre) break;
                }
                count--;

                totCount++;
                totLen += count;
            }
        }
    }
    //模糊度
    float result = (float)totLen / totCount;
    delete[] sobelTable;
    sobelTable = NULL;

    return result;
}

float matLightClearnessFlag(const cv::Mat image,int flag)
{
    Q_UNUSED(image);
    Q_UNUSED(flag);

    return 0;
}

float nameImageClearness(const QString name,int flag)
{
    cv::Mat im = cvRead(name, cv::IMREAD_UNCHANGED);
    if(flag<0){
        return matLightClearness(im);
    }
    return matLightClearnessFlag(im,flag);
}

bool maxInnerRect(const std::vector<cv::Point> con, cv::Rect &R){
    //由于使用矩来求轮廓的重心，并作为扩散的中心点，所以对u形的区域不友好,
    cv::Moments moment = moments(con);
    cv::Point midPoint = cv::Point(int(moment.m10 / moment.m00), int(moment.m01 / moment.m00));
    double Flag = pointPolygonTest(con, midPoint, false);
    if (Flag <= 0) {
        R.x = 0;
        R.y = 0;
        R.width = 0;
        R.height = 0;
        return false;
    }
    cv::Rect rect = boundingRect(con);
    int x1, x2, y1, y2;     //中心扩散的四个顶点坐标
    x1 = midPoint.x - 1;
    x2 = midPoint.x + 1;
    y1 = midPoint.y - 1;
    y2 = midPoint.y + 1;

    int cnt_range, step, radio_x, radio_y;
    int thre = 4;           //由于轮廓并非是很直的线，一个突出点会影响结果，所以要设置敏感值，太小结果不对

    if (rect.width > rect.height) { // 判断轮廓 X方向更长
        cnt_range = rect.width;     //获得长边
    }
    else {
        cnt_range = rect.height;
    }
    bool flag_x1 = false, flag_x2 = false, flag_y1 = false, flag_y2 = false;//定义标志，标记是否到达边缘
    radio_x = rect.width / 6;       //根据区域的外接矩形边来决定x边扩散的步长
    radio_y = rect.height / 6;      //根据区域的外接矩形边来决定y边扩散的步长
    step = cnt_range/120;
    if (step<1) {                   //收缩时步长等于1；step代表每次收缩时，判断点在轮廓外面的步长,必须大于等于1,同时也不能太大，会影响内接矩阵的精度
        step = 1;
    }
    if (step>=3) {
        step = 2;
    }
    //四条边分别求，每条边找到第一次出现在轮廓外的点，然后再收缩，直到找到边界
    //（此处为了让边不要太敏感，设置出现在轮廓外的点大于thre时，才开始收缩）

    for (int ix = 1; ix < cnt_range; ++ix) {
        if (flag_y1 == false) {
            y1 = y1 - radio_y;//每次扩散radio_y行
            int numy1 = 0;
            for (int i = x1; i <= x2;i=i+ step) {
                double p_x1y1 = pointPolygonTest(con, cv::Point(i, y1), false);
                if (p_x1y1 < 0) {
                    numy1++;
                }
                if (numy1 > thre || y1 <= rect.y) {//开始收缩
                    for (int m = 0; m < radio_y -1 ; ++m) {
                        int numy11 = 0;
                        y1 = y1+ 1;     // 每次收缩1行
                        for (int j = x1; j <= x2; j=j+ step) {
                            double p_jy1 = pointPolygonTest(con, cv::Point(j, y1), false);
                            if (p_jy1 < 0) {
                                numy11++;
                            }
                            if (numy11 > thre)
                                break;//继续收缩
                        }
                        if (numy11 > thre)
                            continue;//继续收缩
                        else
                            break;//找到结果收缩结束
                    }
                    flag_y1 = true;
                    break;//找到结果收缩结束
                }
            }
        }
        if (flag_x1 == false) {
            x1 = x1 - radio_x;
            int numx1 = 0;
            for (int i = y1; i <= y2; i = i + step) {
                double p_x1i = pointPolygonTest(con, cv::Point(x1, i), false);
                if (p_x1i < 0) {
                    numx1++;
                }
                if (numx1 > thre || x1<= rect.x) {//开始收缩
                    for (int m = 0; m < radio_x - 1; ++m) {
                        int numx11 = 0;
                        x1 = x1 + 1;    //每次收缩1行
                        for (int j = y1; j <= y2; j = j + step) {
                            double p_x1j = pointPolygonTest(con, cv::Point(x1, j), false);
                            if (p_x1j < 0) {
                                numx11++;
                            }
                            if (numx11 > thre)
                                break;
                        }
                        if (numx11 > thre)
                            continue;
                        else
                            break;
                    }
                    flag_x1 = true;
                    break;
                }
            }
        }
        if (flag_y2 == false) {
            y2 = y2 + radio_y;
            int numy2 = 0;
            for (int i = x1; i <= x2; i =i + step) {
                double p_iy2 = pointPolygonTest(con, cv::Point(i, y2), false);
                if (p_iy2 < 0) {
                    numy2++;
                }
                if (numy2 > thre || y2 >= (rect.y+rect.height)) {       //开始收缩
                    for (int m = 0; m < radio_y - 1; ++m) {
                        int numy22 = 0;
                        y2 = y2 - 1;      //  每次收缩1行
                        for (int j = x1; j <= x2; j = j + step) {
                            double p_jy2 = pointPolygonTest(con, cv::Point(j, y2), false);
                            if (p_jy2 < 0) {
                                numy22++;
                            }
                            if (numy22 > thre)
                                break;
                        }
                        if (numy22 > thre)
                            continue;
                        else
                            break;
                    }
                    flag_y2 = true;
                    break;
                }
            }
        }

        if (flag_x2 == false) {
            x2 = x2 + radio_x;
            int numx2 = 0;
            for (int i = y1; i <= y2; i = i + step) {
                double p_x2i = pointPolygonTest(con, cv::Point(x2, i), false);
                if (p_x2i < 0) {
                    numx2++;
                }
                if (numx2 > thre || x2 >= (rect.x + rect.width)) {//开始收缩
                    for (int m = 0; m < radio_x - 1; ++m) {
                        int numx22 = 0;
                        x2 = x2 - 1;    // 每次收缩1行
                        for (int j = y1; j <= y2; j=j+ step) {
                            double p_x2j = pointPolygonTest(con, cv::Point(x2, j), false);
                            if (p_x2j < 0) {
                                numx22++;
                            }
                            if (numx22 > thre)
                                break;
                        }
                        if (numx22 > thre)
                            continue;
                        else
                            break;
                    }
                    flag_x2 = true;
                    break;
                }
            }
        }
        if (flag_y1 && flag_x1 && flag_y2 && flag_x2) {
            break;
        }
    }

    R.x = x1;
    R.y = y1;
    R.width = x2 - x1;
    R.height = y2 - y1;
    if(R.x<=0 || R.y<=0 || R.width<=0 || R.height<=0)
        return false;
    return true;
}

void blackImageBox(cv::Mat &image, cv::Rect box)
{//图像BOX以外填充黑色
    cv::Mat temp = image(box).clone();
    image = cv::Scalar(0,0,0);
    cv::Mat t = image(box);
    temp.copyTo(t);
}

int blackImageBorderBox(cv::Mat &image,const cv::Rect box,const QSize winSize,const QSize borderSize)
{
    int bType = 0;
    int leftWidth = box.x;
    int rightWidth = winSize.width() - box.width - box.x;
//    int topHeight = box.y;
    int bottomHeight = winSize.height() - box.height - box.y;

    if(box.x == 0 || box.y == 0 || (box.x+box.width) == winSize.width() || (box.y+box.height) == winSize.height()){
        //增加白边.判断左上角还是右上角
//        int dw=80,dh=40;
        if(leftWidth<rightWidth){
            //左上角
            bType=1;
            int dw = borderSize.width();
            int dh = borderSize.height();
            for(int i=0;i<dh;i++){
                if(box.y == 0){
                    cv::line(image,cv::Point(0,box.y+i),cv::Point(box.width-1,box.y+i),cv::Scalar(0,0,0),1,8,0);
                }
                if((box.y+box.height) == winSize.height()){
                    cv::line(image,cv::Point(0,box.y+box.height-dh+i),cv::Point(box.width-1,box.y+box.height-dh+i),cv::Scalar(0,0,0),1,8,0);
                }
            }
            for(int i=0;i<dw;i++){
                if(box.x == 0){
                    cv::line(image,cv::Point(box.x+i,box.y),cv::Point(box.x+i,box.y+box.height-1),cv::Scalar(0,0,0),1,8,0);
                }
                if((box.x+box.width) == winSize.width()){
                    cv::line(image,cv::Point(box.x+box.width-dw+i,box.y),cv::Point(box.x+box.width-dw+i,box.y+box.height-1),cv::Scalar(0,0,0),1,8,0);
                }
            }
        }else{
            //右上角
            bType=2;
            int dw = std::max(borderSize.width(),rightWidth);
            int dh = std::max(borderSize.height(),bottomHeight);
            for(int i=0;i<dh;i++){
                if(box.y == 0){
                    cv::line(image,cv::Point(box.x,box.y+i),cv::Point(box.x+box.width-1,box.y+i),cv::Scalar(0,0,0),1,8,0);
                }
                if((box.y+box.height) == winSize.height()){
                    cv::line(image,cv::Point(box.x,box.y+box.height-dh+i),cv::Point(box.x+box.width-1,box.y+box.height-dh+i),cv::Scalar(0,0,0),1,8,0);
                }
            }
            for(int i=0;i<dw;i++){
                if(box.x == 0){
                    cv::line(image,cv::Point(box.x+i,box.y),cv::Point(box.x+i,box.y+box.height-1),cv::Scalar(0,0,0),1,8,0);
                }
                if((box.x+box.width) == winSize.width()){
                    cv::line(image,cv::Point(box.x+box.width-dw+i,box.y),cv::Point(box.x+box.width-dw+i,box.y+box.height-1),cv::Scalar(0,0,0),1,8,0);
                }
            }
        }
    }
    return bType;
}

int getImageContoursMax(const std::vector<std::vector<cv::Point>> contours,const std::vector<cv::Vec4i>hierarchy,
                        cv::Rect &maxBox,int &maxArea,int MinWidth,int MinHeight)
{//获取最大一级轮廓面积外框
    int pos = -1;
    int minW = MinWidth,minH = MinHeight;
    if(MinWidth<0){
        minW = MinWidth/2;
    }
    if(MinHeight<0){
        minH = MinHeight/2;
    }
    maxArea = 0;
    for(size_t t=0;t<contours.size();t++){
//        int p1 = hierarchy[t][3];
//        int p2 = hierarchy[p1][3];
        if(hierarchy[t][3] > 0){
            //判断非一级
            continue;
        }
        int area = contourArea(contours[t]);
        if(maxArea ==0 || maxArea < area ){
            maxBox = boundingRect(contours[t]);
            if(maxBox.width < minW || maxBox.height < minH){
                //最小轮廓限制
                continue;
            }
            maxArea = area;
            pos = (int)t;
        }
    }
    return pos;
}

void setLabelRGB(QLabel *label,int r,int g,int b){
    label->setText("");
    label->setStyleSheet(QString("QLabel{background-color:rgb(%0,%1,%2)}").arg(r).arg(g).arg(b));
}

QString getRGB(int r,int g,int b)
{
    return QString("#%0%1%2").arg(r,2,16,QLatin1Char('0')).arg(g,2,16,QLatin1Char('0')).arg(b,2,16,QLatin1Char('0'));
}

QString getRed(void)
{
    return QString("color: red");
}

void procImageHdr(const cv::Mat highMat,const cv::Mat normalMat,const cv::Mat lowMat,cv::Mat &hdrMat,const float w1,const float w2)
{
    //3张图片大小一致
    int i,j;
    int highWidth,highHeight;
    int normalWidth,normalHeight;
    int lowWidth,lowHeight;

    //接着获取到图片的width和height
    highWidth = highMat.rows;
    highHeight = highMat.cols;
    normalWidth = normalMat.rows;
    normalHeight = normalMat.cols;
    lowWidth = lowMat.rows;
    lowHeight = lowMat.cols;

    cv::Mat tmpMat;

    //创建空白图片：tmp_mat
    tmpMat = cv::Mat(normalWidth,normalHeight,CV_8UC1, cv::Scalar(0));
    if(normalMat.type() == CV_8UC3){
        cv::cvtColor(normalMat, tmpMat, cv::COLOR_BGR2GRAY);
    }else{
        tmpMat = normalMat.clone();
    }
    cv::Vec3b p1,p3;
    uchar c1,c2,c3;

    float weight;

    //HDR的算法处理：权重计算，把过曝和欠曝图片合成到dst_mat中
    for(i=0; i< normalWidth; i++){
        for(j=0; j<normalHeight; j++){
            if(normalMat.type() == CV_8UC3){
                p1 = highMat.at<cv::Vec3b>(i,j);
                p3 = lowMat.at<cv::Vec3b>(i,j);
            }else{
                c1 = highMat.at<uchar>(i,j);
                c3 = lowMat.at<uchar>(i,j);
            }
            c2 = tmpMat.at<uchar>(i,j);
            weight = w1 + (127 - c2) * w2;
            if(normalMat.type() == CV_8UC3){
                p3[0] = (p1[0] * weight) + (p3[0] *(1-weight));
                p3[1] = (p1[1] * weight) + (p3[1] *(1-weight));
                p3[2] = (p1[2] * weight) + (p3[2] *(1-weight));
                hdrMat.at<cv::Vec3b>(i,j) = p3;
            }else{
                c3 = (c1 * weight) + (c3 *(1-weight));
                hdrMat.at<uchar>(i,j) = c3;
            }
        }
    }
}

QString getFileMd5(const QString filePath){
    QString md5="";
    QFile file(filePath);
    if(file.open(QIODevice::ReadOnly)){
        qDebug() << "打开文件成功";
        //这里 QCryptographicHash::Md5 是个枚举类型，可以说改成你需要的比如Sha1、Sha3
        QByteArray array = QCryptographicHash::hash(file.readAll(), QCryptographicHash::Md5).toHex();
        file.close();
        md5.append(array);
    }
    return md5;
}

QString getFileBase64Content(const QString path)
{
    const std::string base64_chars =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
        "0123456789+/";
    QString ret="";
    int i = 0;
    int j = 0;
    unsigned char char_array_3[3];
    unsigned char char_array_4[4];
    unsigned int bufferSize = 1024;
    unsigned char buffer[1024];

    std::ifstream file_read;
    file_read.open(path.toStdString(), std::ios::binary);
    while (!file_read.eof())
    {
        file_read.read((char *) buffer, bufferSize * sizeof(char));
        int num = file_read.gcount();
        int m = 0;
        while (num--)
        {
            char_array_3[i++] = buffer[m++];
            if(i == 3)
            {
                char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                char_array_4[3] = char_array_3[2] & 0x3f;
                for(i = 0; (i<4) ; i++)
                {
                    ret += base64_chars[char_array_4[i]];
                }
                i = 0;
            }
        }
    }
    file_read.close();
    if(i)
    {
        for(j = i; j < 3; j++)
        {
            char_array_3[j] = '\0';
        }

        char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
        char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
        char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
        char_array_4[3] = char_array_3[2] & 0x3f;
        for(j = 0; (j < i + 1); j++)
        {
            ret += base64_chars[char_array_4[j]];
        }
        while((i++ < 3))
        {
            ret += '=';
        }
    }
    // if (urlencoded)
    // {
    //     ret = curl_escape(ret.c_str(), ret.length());
    // }
    return ret;
}

